package org.jflame.auth.session;

import org.jflame.auth.LoginUser;
import org.jflame.auth.authc.AuthcException;
import org.jflame.auth.authc.AuthcException.AuthcError;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;

import org.apache.commons.lang3.Validate;

public class ConcurrentSessionControlService {

    private final SessionRegistry sessionRegistry;

    private boolean exceptionIfMaximumExceeded = false;

    private int maximumSessions = 1;

    public ConcurrentSessionControlService(SessionRegistry sessionRegistry) {
        Validate.notNull(sessionRegistry, "The sessionRegistry cannot be null");
        this.sessionRegistry = sessionRegistry;
    }

    public void onAuthentication(final LoginUser authentication, final SessionAdapter sessionOperation)
            throws AuthcException {
        int allowedSessions = getMaximumSessionsForThisUser(authentication);
        if (allowedSessions == -1) {
            return;
        }
        List<SessionInfo> sessions = sessionRegistry.getAllSessions(authentication.getUserName(), false);
        int sessionCount = sessions.size();
        if (sessionCount < allowedSessions) {
            return;
        }
        if (sessionCount == allowedSessions) {
            Optional<String> sessId = sessionOperation.getSessionId(false);
            if (sessId.isPresent()) {
                // 有个相同sessionid
                for (SessionInfo si : sessions) {
                    if (si.getSessionId()
                            .equals(sessId.get())) {
                        return;
                    }
                }
            }
        }
        if (exceptionIfMaximumExceeded) {
            throw new AuthcException(AuthcError.MaximumSessionExceeded);
        }
        allowableSessionsExceeded(sessions, allowedSessions, this.sessionRegistry);
    }

    protected boolean allowableSessionsExceeded(final List<SessionInfo> sessions, final int allowableSessions,
            final SessionRegistry registry) {
        // 超出了允许登录,按最后一次使用时间顺序,踢除多余的
        sessions.sort(Comparator.comparing(SessionInfo::getLastRequest));
        int maximumSessionsExceededBy = sessions.size() - allowableSessions + 1;
        List<SessionInfo> sessionsToBeExpired = sessions.subList(0, maximumSessionsExceededBy);
        for (SessionInfo session : sessionsToBeExpired) {
            session.expireNow();
        }
        return true;
    }

    public void setExceptionIfMaximumExceeded(boolean exceptionIfMaximumExceeded) {
        this.exceptionIfMaximumExceeded = exceptionIfMaximumExceeded;
    }

    /**
     * 设置一个账号允许的最大会话数量,默认值1,-1表示不限制
     * 
     * @param maximumSessions
     */
    public void setMaximumSessions(int maximumSessions) {
        if (maximumSessions <= 0) {
            maximumSessions = -1;
        }
        this.maximumSessions = maximumSessions;
    }

    protected int getMaximumSessionsForThisUser(LoginUser authentication) {
        return this.maximumSessions;
    }

    public SessionRegistry getSessionRegistry() {
        return sessionRegistry;
    }

    public int getMaximumSessions() {
        return maximumSessions;
    }

}
